home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C++ / Frameworks / Sprocket Framework DR2 / Sprocket Framework / MenuBar.cp < prev    next >
Text File  |  1996-06-15  |  13KB  |  601 lines

  1. /*
  2.  
  3.     File:        MenuBar.cp
  4.     Project:    Sprocket Framework 1.1 (DR2), released 6/15/96
  5.     Contains:    A MenuBar class deliberately designed to resemble ODMenuBar from OpenDoc™
  6.     To Do:        ?
  7.  
  8.     Sprocket Major Contributors:
  9.     ----------------------------
  10.     Dave Falkenburg, producer of Sprocket 1.0
  11.     Bill Hayden,     producer of Sprocket 1.1
  12.     Steve Sisak,     producer of the upcoming Sprocket 2.0
  13.     
  14.     Pete Alexander        Steve Falkenburg    Randy Thelen
  15.     Eric Berdahl        Nitin Ganatra        Chris K. Thomas
  16.     Marshall Clow        Dave Hershey        Leonard Rosenthal
  17.     Tim Craycroft        Dave Mark            Dean Yu
  18.     David denBoer        Gary Powell
  19.     Cameron Esfahani    Jon Summers            Apple Computer, Inc.
  20.         
  21.     Comments, Additions, or Corrections:
  22.     ------------------------------------
  23.     Bill Hayden, Nikol Software <nikol@codewell.com>
  24.  
  25. */
  26.  
  27.  
  28. #include "MenuBar.h"
  29. #include "Sprocket.h"
  30. #include "StandardMenus.h"
  31.  
  32. Boolean        TMenuBar::fgMenuBarNeedsRedraw = true;
  33. Boolean        TMenuBar::fgMenuBarHidden = false;
  34. short        TMenuBar::fgMenuBarHeight = 20;
  35. RgnHandle    TMenuBar::fgMenuBarRgn = nil;
  36.  
  37.  
  38.     inline UInt32 BuildKey(UInt16 hiword, UInt16 loword)
  39.     {
  40.         return (((UInt32) hiword << 16) | loword);
  41.     }
  42.  
  43. TMenuItemTable::CompareResult
  44. TMenuItemTable::Compare(ArrayElementPtr element1,ArrayElementPtr element2)
  45. {
  46.     UInt32    key1 = BuildKey(((MenuMapping *) element1)->fMenu, ((MenuMapping *) element1)->fItem);
  47.     UInt32    key2 = BuildKey(((MenuMapping *) element2)->fMenu, ((MenuMapping *) element2)->fItem);
  48.     
  49.     return    (key2 - key1);
  50. }
  51.  
  52.  
  53. TMenuCommandTable::CompareResult
  54. TMenuCommandTable::Compare(ArrayElementPtr element1, ArrayElementPtr element2)
  55. {
  56.     return (((MenuMapping *) element2)->fCommand - ((MenuMapping *) element1)->fCommand);
  57. }
  58.  
  59.  
  60.  
  61. /*****************************************************************************/
  62.  
  63.  
  64.  
  65. OSErr TMenuBar::GetNewMenuBar(short whichMBAR)
  66. {
  67.     MenuBarResource ** mbarResource = (MenuBarResource **) GetResource('MBAR', whichMBAR);
  68.     
  69.     if (mbarResource)
  70.         {
  71.         UInt16    menuCount;
  72.         
  73.         fCurrentMBAR = whichMBAR;
  74.         
  75.         HLock((Handle) mbarResource);
  76.         
  77.         menuCount = (**mbarResource).numberOfMenus;
  78.         
  79.         fgMenuBarHeight = GetMBarHeight();
  80.         
  81.         for (UInt16 menuIndex = 0; menuIndex < menuCount; menuIndex++)
  82.             {
  83.             SInt16    whichMenu = (**mbarResource).menuIDList[menuIndex];
  84.             MenuRef    theMenu;
  85.  
  86.             //    try to make the MenuRef from a 'CMNU' which allows us to
  87.             //    automatically register any commands we find in the resource.
  88.             
  89.             theMenu = this->GetMenuFromCMNU(whichMenu);
  90.             if (theMenu == NULL)
  91.                 {
  92.                 //    no 'CMNU' was found, so go ahead and use a 'MENU'
  93.                 //    resource, knowing that we must register commands
  94.                 //    manually.
  95.                 
  96.                 theMenu = GetMenu(whichMenu);
  97.                 }
  98.  
  99.             //    Add the menu to the end of the menubar
  100.             if (theMenu)
  101.                 InsertMenu(theMenu, 0);
  102.             else
  103.                 return resNotFound;
  104.             }
  105.         
  106.         //    force a redraw of the menubar at the next possible opportunity
  107.         
  108.         fgMenuBarNeedsRedraw = true;
  109.         
  110.         HUnlock((Handle) mbarResource);
  111.         ReleaseResource((Handle) mbarResource);
  112.         }
  113.     else
  114.         return resNotFound;
  115.         
  116.     return noErr;
  117. }
  118.  
  119.  
  120.  
  121.  
  122. /*****************************************************************************/
  123.  
  124.  
  125.  
  126. //    Define some functions to help us walk through CMNU resources
  127. //    (this should make the code a bit more readable)
  128.  
  129. static CommandID *FindMenuCommandPtrFromCMNUItem(CMNUItemData *currentItem);
  130. static CMNUItemData *FindNextCMNUItem(CMNUItemData *currentItem);
  131.  
  132.  
  133. static CommandID *FindMenuCommandPtrFromCMNUItem(CMNUItemData *currentItem)
  134. {
  135.     Byte * p = (Byte *) currentItem;
  136.     
  137.     if ((*p) == NULL)        //    we’re at the end of the CMNU!
  138.         return NULL;
  139.     
  140.     p +=        (*p) + 1        //    itemString[0], a.k.a. the length
  141.             +    sizeof(Byte)    //    itemIcon
  142.             +    sizeof(Byte)    //    itemCmd
  143.             +    sizeof(Byte)    //    itemMark
  144.             +    sizeof(Style);    //    itemStyle
  145.     p = (Byte *) ((((long) p) + 1) & ~1);    //    align up to the next even boundary
  146.     
  147.     return (CommandID *) p;
  148. }
  149.  
  150.  
  151. static CMNUItemData *FindNextCMNUItem(CMNUItemData *currentItem)
  152. {
  153.     return (CMNUItemData *)(FindMenuCommandPtrFromCMNUItem(currentItem) + 1);
  154. }
  155.  
  156.  
  157.  
  158. /*****************************************************************************/
  159.  
  160.  
  161.  
  162. MenuRef TMenuBar::GetMenuFromCMNU(short whichMenu)
  163. {
  164.     CMNUResource ** theCMNU = (CMNUResource **) GetResource('CMNU', whichMenu);
  165.     MenuRef            newMenuRef = NULL;
  166.  
  167.     if (theCMNU)
  168.         {
  169.         HLock((Handle) theCMNU);
  170.  
  171.         MenuID            theMenuID = (**theCMNU).menuID;
  172.         MenuItemID        itemNum = 1;
  173.         CommandID    theCommand;
  174.         short            cmdChar;
  175.         
  176.         if(whichMenu != theMenuID)
  177.             DebugMessage("\pSprocket has encountered a non-matching menu resource ID and menu ID.");
  178.         
  179.         //    Make a new MenuRef from the CMNU data
  180.         newMenuRef = NewMenu(theMenuID, (**theCMNU).menuTitle);
  181.  
  182.         //    MENU & CMNU resources suck, don’t they?
  183.         Byte * p = (Byte *) (**theCMNU).menuTitle;
  184.  
  185.         //    Don’t forget to skip past string and length byte
  186.         p += *p + 1;
  187.  
  188.         CMNUItemData * theItemData = (CMNUItemData *) p;
  189.         
  190.         while (theItemData->itemString[0])        //    do we have any menu items
  191.             {
  192.             p = (Byte *) theItemData;
  193.             p += *p + 1;
  194.             
  195.             //    use the item data to build a new menuitem
  196.             ::AppendMenu(newMenuRef, theItemData->itemString);
  197.             ::SetItemIcon(newMenuRef, itemNum, *p++);
  198.             ::SetItemCmd(newMenuRef, itemNum, *p++);
  199.             ::SetItemMark(newMenuRef, itemNum, *p++);
  200.             ::SetItemStyle(newMenuRef, itemNum, *p++);
  201.  
  202.             //    deal with any disabled items
  203.             if (!((**theCMNU).enableFlags & (1 << itemNum)))
  204.                 DisableItem(newMenuRef,itemNum);
  205.  
  206.             //    align up to the next even boundary
  207.             p = (Byte *) ((((long) p) + 1) & ~1);
  208.             
  209.             //    register the menu command, if any
  210.             theCommand = *((CommandID *) p);
  211.             if (theCommand)
  212.                 this->RegisterCommand(theCommand, theMenuID, itemNum);
  213.                 
  214.             //    insert a submenu if this item has one
  215.             ::GetItemCmd(newMenuRef, itemNum, &cmdChar);
  216.             if (cmdChar == hMenuCmd)
  217.                 {
  218.                 MenuRef    aSubmenu;
  219.                 
  220.                 ::GetItemMark(newMenuRef, itemNum, &cmdChar);
  221.                 aSubmenu = GetMenuFromCMNU(cmdChar);
  222.                 if (!aSubmenu)
  223.                     aSubmenu = GetMenu(cmdChar);
  224.                     
  225.                 if (aSubmenu)
  226.                     ::InsertMenu(aSubmenu, -1);
  227.                 else
  228.                     DebugMessage("\pNon-existant submenu specified in TMenuBar::GetMenuFromCMNU");
  229.                 }
  230.  
  231.             theItemData = FindNextCMNUItem(theItemData);
  232.             itemNum++;
  233.             }
  234.  
  235.         ReleaseResource((Handle) theCMNU);
  236.         }
  237.  
  238.     return newMenuRef;
  239. }
  240.  
  241.  
  242.  
  243. /*****************************************************************************/
  244.  
  245.  
  246.  
  247. //    find the menu command in the array, given the menu and item
  248.  
  249. CommandID TMenuBar::GetCommand(MenuID menu, MenuItemID item)
  250. {
  251.     MenuMapping        key = {menu, item, kNoMenuCommandID};
  252.     MenuMapping    *    foundMapping;
  253.     
  254.     foundMapping = (MenuMapping *) fMenuItemTable.Find(&key);
  255.  
  256.     if (foundMapping)
  257.         return foundMapping->fCommand;
  258.         
  259.     return kNoMenuCommandID;
  260. }
  261.  
  262.  
  263.  
  264. /*****************************************************************************/
  265.  
  266.  
  267.  
  268. //    find the menu and item in the array, given the menu command
  269.     
  270. void TMenuBar::GetMenuAndItem(CommandID commandNum,
  271.                               MenuID * returnedMenu,
  272.                               MenuItemID * returnedItem)
  273. {
  274.     MenuMapping        key = {kNoMenuID,kNoMenuItemID,commandNum};
  275.     MenuMapping    *    foundMapping;
  276.  
  277.     foundMapping = (MenuMapping *) fCommandTable.Find(&key);
  278.  
  279.     if (foundMapping)
  280.         {
  281.         *returnedMenu = foundMapping->fMenu;
  282.         *returnedItem = foundMapping->fItem;
  283.         }
  284.     else
  285.         {
  286.         *returnedMenu = kNoMenuID;
  287.         *returnedItem = kNoMenuItemID;
  288.         }
  289. }
  290.  
  291.  
  292.  
  293. /*****************************************************************************/
  294.  
  295.  
  296.  
  297. OSErr TMenuBar::RegisterCommand(CommandID commandNum, MenuID menu, MenuItemID item)
  298. {
  299.     MenuMapping    * aMapping = new MenuMapping;
  300.     
  301.     if (aMapping == NULL)
  302.         return MemError();
  303.         
  304.     aMapping->fMenu = menu;
  305.     aMapping->fItem = item;
  306.     aMapping->fCommand = commandNum;
  307.     
  308.     fCommandTable.Add(aMapping);
  309.     fMenuItemTable.Add(aMapping);
  310.     
  311.     return noErr;
  312. }
  313.  
  314.  
  315.  
  316. /*****************************************************************************/
  317.  
  318.  
  319.  
  320. OSErr TMenuBar::UnregisterCommand(CommandID commandNum)
  321. {
  322.     MenuMapping    key = {kNoMenuID, kNoMenuItemID, commandNum};
  323.     
  324.     return noErr;
  325. }
  326.  
  327.     
  328.     
  329. /*****************************************************************************/
  330.  
  331.  
  332.  
  333. MenuRef TMenuBar::GetMenuRefAndItemFromCommand(CommandID commandNum, MenuID *menu, MenuItemID *item)
  334. {
  335.     this->GetMenuAndItem(commandNum, menu, item);
  336.     if (*menu != kNoMenuID)
  337.         return GetMenuHandle(*menu);
  338.     else
  339.         return NULL;
  340. }
  341.  
  342.  
  343.  
  344. /*****************************************************************************/
  345.  
  346.  
  347.  
  348. void TMenuBar::EnableCommand(CommandID commandNum, Boolean enable)
  349. {
  350.     MenuRef            menuHandle;
  351.     MenuID            menu;
  352.     MenuItemID        item;
  353.     
  354.     menuHandle = this->GetMenuRefAndItemFromCommand(commandNum, &menu, &item);
  355.     if (menuHandle)
  356.         {
  357.         if (enable)
  358.             EnableItem(menuHandle, item);
  359.         else
  360.             DisableItem(menuHandle,item);
  361.         }
  362. }
  363.  
  364.     
  365. /*****************************************************************************/
  366.  
  367.  
  368.  
  369. void TMenuBar::EnableAndCheckCommand(CommandID commandNum, Boolean enable, Boolean check)
  370. {
  371.     MenuRef            menuHandle;
  372.     MenuID            menu;
  373.     MenuItemID        item;
  374.     
  375.     menuHandle = this->GetMenuRefAndItemFromCommand(commandNum, &menu, &item);
  376.     if (menuHandle)
  377.         {
  378.         CheckItem(menuHandle, item, check);
  379.  
  380.         if (enable)
  381.             EnableItem(menuHandle, item);
  382.         else
  383.             DisableItem(menuHandle, item);
  384.         }
  385. }
  386.  
  387.  
  388.  
  389. /*****************************************************************************/
  390.  
  391.  
  392.  
  393. void TMenuBar::GetItemString(CommandID commandNum, StringPtr itemString)
  394. {
  395.     MenuRef            menuHandle;
  396.     MenuID            menu;
  397.     MenuItemID        item;
  398.     
  399.     menuHandle = this->GetMenuRefAndItemFromCommand(commandNum, &menu, &item);
  400.     if (menuHandle)
  401.         GetMenuItemText(menuHandle, item, itemString);
  402. }
  403.  
  404.  
  405.  
  406. /*****************************************************************************/
  407.  
  408.  
  409.  
  410. void TMenuBar::SetItemString(CommandID commandNum, StringPtr itemString)
  411. {
  412.     MenuRef            menuHandle;
  413.     MenuID            menu;
  414.     MenuItemID        item;
  415.     
  416.     menuHandle = this->GetMenuRefAndItemFromCommand(commandNum, &menu, &item);
  417.     if (menuHandle)
  418.         SetMenuItemText(menuHandle, item, itemString);
  419. }
  420.  
  421.  
  422.  
  423. /*****************************************************************************/
  424.  
  425.  
  426.  
  427. void TMenuBar::SetItemStyle(CommandID commandNum, Style aStyle)
  428. {
  429.     MenuRef            menuHandle;
  430.     MenuID            menu;
  431.     MenuItemID        item;
  432.     
  433.     menuHandle = this->GetMenuRefAndItemFromCommand(commandNum, &menu, &item);
  434.     if (menuHandle)
  435.         ::SetItemStyle(menuHandle, item, aStyle);
  436. }
  437.  
  438.     
  439.  
  440. /*****************************************************************************/
  441.  
  442.  
  443.  
  444. void TMenuBar::RedrawIfNeeded()
  445. {
  446.     if (fgMenuBarNeedsRedraw && !fgMenuBarHidden)
  447.         {
  448.         DrawMenuBar();
  449.         fgMenuBarNeedsRedraw = false;
  450.         }
  451. }
  452.     
  453.     
  454.     
  455. /*****************************************************************************/
  456.  
  457.  
  458.  
  459. void TMenuBar::Invalidate()
  460. {
  461.     fgMenuBarNeedsRedraw = true;
  462. }
  463.  
  464.  
  465.     
  466.  
  467. /*****************************************************************************/
  468.  
  469.  
  470. void TMenuBar::Validate()
  471. {
  472.     fgMenuBarNeedsRedraw = false;
  473. }
  474.  
  475.  
  476.  
  477. /*****************************************************************************/
  478.  
  479.  
  480.  
  481. void TMenuBar::HideMenuBar()
  482. {
  483.     Rect            mBarRect;
  484.         
  485.  
  486.     if (fgMenuBarHidden)                            // It was already hidden
  487.         return;
  488.         
  489.     LMSetMBarHeight(0);                                // make the Menu Bar's height zero
  490.     
  491.     fgMenuBarRgn = NewRgn();
  492.     mBarRect = qd.screenBits.bounds;                // create a rect for the mbar
  493.     mBarRect.bottom = mBarRect.top + fgMenuBarHeight;
  494.     RectRgn(fgMenuBarRgn, &mBarRect);                // make a region for the mbar
  495.  
  496.     RgnHandle        GrayRgn = LMGetGrayRgn();
  497.  
  498.     UnionRgn(GrayRgn,fgMenuBarRgn,GrayRgn);            // tell the desktop it covers the menu bar
  499.  
  500.     WindowRef    wpFirst = LMGetWindowList();
  501.     
  502.     PaintBehind(wpFirst, fgMenuBarRgn);                // redraw windows behind front    
  503.     CalcVisBehind(wpFirst, fgMenuBarRgn);            // redraw windows behind front
  504.     
  505.     fgMenuBarHidden = true;
  506. }
  507.  
  508.  
  509.  
  510. /*****************************************************************************/
  511.  
  512.  
  513.  
  514. void TMenuBar::ShowMenuBar()
  515. {
  516.     RgnHandle        GrayRgn = LMGetGrayRgn();
  517.  
  518.  
  519.     if (fgMenuBarRgn)                                // i.e. HideMenuBar has already been called
  520.         {
  521.         LMSetMBarHeight(fgMenuBarHeight);            // make the menu bar's height normal
  522.         
  523.         DiffRgn(GrayRgn, fgMenuBarRgn, GrayRgn);    // remove the menu bar from the desktop
  524.         DisposeRgn(fgMenuBarRgn);                    // dispose the bar region
  525.         }
  526.         
  527.     DrawMenuBar();
  528.  
  529.     fgMenuBarNeedsRedraw = false;
  530.     fgMenuBarHidden = false;
  531. }
  532.  
  533.  
  534.  
  535. /*****************************************************************************/
  536.  
  537.  
  538.  
  539. OSErr TMenuBar::HiliteMenusForModalDialog(Boolean hiliting)
  540. {
  541.     MenuBarResource ** mbarResource = (MenuBarResource **) GetResource('MBAR', fCurrentMBAR);
  542.     
  543.     if (mbarResource)
  544.         {
  545.         UInt16    menuCount;
  546.         
  547.         this->EnableCommand( cAbout, hiliting );    // Leave DA's active, as they should be
  548.  
  549.         HLock((Handle) mbarResource);
  550.         
  551.         menuCount = (**mbarResource).numberOfMenus;
  552.         
  553.         for (short menuIndex = 0; menuIndex < menuCount; menuIndex++)
  554.             {
  555.             MenuRef    theMenu;
  556.             SInt16    whichMenu;
  557.             
  558.             whichMenu = (**mbarResource).menuIDList[menuIndex];
  559.  
  560.             if (whichMenu == mApple)    // Apple menu already handled
  561.                 continue;
  562.                 
  563.             theMenu = GetMenuHandle(whichMenu);
  564.  
  565.             //    Enable or disable the menu as appropriate
  566.             
  567.             if (theMenu)
  568.                 {
  569.                 if (hiliting)
  570.                     EnableItem(theMenu, 0);
  571.                 else
  572.                     {
  573.                     if (whichMenu == mEdit)
  574.                         {
  575.                         for (short x = 1; x <= CountMItems(theMenu); x++)
  576.                             {
  577.                             DisableItem(theMenu, x);
  578.                             }
  579.                         }
  580.                     else
  581.                         DisableItem(theMenu, 0);
  582.                     }
  583.                 }
  584.             else
  585.                 return resNotFound;
  586.             }
  587.         
  588.         //    force a redraw of the menubar at the next possible opportunity
  589.         
  590.         fgMenuBarNeedsRedraw = true;
  591.         
  592.         HUnlock((Handle) mbarResource);
  593.         ReleaseResource((Handle) mbarResource);
  594.         }
  595.     else
  596.         return resNotFound;
  597.     
  598.     return noErr;
  599. }
  600.  
  601.